package com.tool.cn.use.map;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.tool.cn.util.DateUtil;
import com.tool.cn.util.JsonUtil;



/**
 * 数据按存储秒数自动删除Map
 * @author wangzh
 * @date 2018年10月23日 上午10:52:01
 */
public final class TimeHashMap<T> {
	
	private final Logger log = LoggerFactory.getLogger(this.getClass()); 
	
	/**
	 * 辅助存储数据对象：key：时间，value:数据list
	 */
	private  Map<Long,List<String>> keyMap=new HashMap<>();
	
	/**
	 * 数据存储对象：key:数据key  value：数据value
	 */
	private  Map<String,T> dataMap=new HashMap<>();
	
	/**
	 * key 为key，value:删除时间
	 */
	private Map<String,Long> checkTime=new HashMap<>();
	
	
	/**
	 * 读写锁
	 */
	ReadWriteLock lock = new ReentrantReadWriteLock();
	private final Lock read = lock.readLock();    //读锁
    private final Lock write = lock.writeLock();    //写锁
	
	/**
	 * 构造方法
	 */
	public TimeHashMap(){
		keyMap=new HashMap<>();
		dataMap=new HashMap<>();
		TimerTask task=this.new clearTime();
		new Timer().schedule(task, new Date(), 1000); //一秒运行一次  
	}
	
	/**
	 * 获取值
	 */
	public T getDataValue(String key){
		
		read.lock();
		try {
			if(dataMap.containsKey(key)) {
				return dataMap.get(key);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			read.unlock();
		}
		return null;
	}
	
	/**
	 * 验证key是否存在
	 * @param key
	 * @return
	 */
	public boolean containsKey(String key) {
		return dataMap.containsKey(key);
	}
	
	/**
	 * 更新值
	 */
	public void updateDataValue(String key,T value){
		// 加写锁
        write.lock();
        
		try {
			if(dataMap.containsKey(key)) {
				dataMap.put(key, value);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			 // 释放写锁
            write.unlock();
		}
	}
	
	/**
	 * 添加永久存储值
	 * @param key key
	 * @param data value
	 */
	public void addData(String key,T data){
		addData(key,data, 0);
	}
	
	/**
	 * 更新数据存储时间
	 * @param key
	 * @param second
	 */
	public boolean changeTime(String key,int second) {
		if(second<0){
			log.error("Set Time Less Than 0");
			return false;
		}
		
		Long timekey;
		if(second==0){
			timekey=0L;
		}else{
			timekey=Long.valueOf(DateUtil.dateToUTC()+second);
		}
		
		write.lock();
		try {
			List<String> list;
			if(!keyMap.containsKey(timekey)){
				list=new ArrayList<String>();
			}else {
				list=keyMap.get(timekey);
			}
			
			list.add(key);
			keyMap.put(timekey, list);
			
			//更新key存活时间
			if(timekey!=0) {
				checkTime.put(key, timekey);
			}
			
		} catch (Exception e) {
			log.error("Update Key:"+key+" Time  Error",e);
			return false;
		}finally {
			 // 释放写锁
            write.unlock();
		}
		return true;
	}
	
	/**
	 * 添加数据
	 * @param data 数据
	 * @param second 时间，单位秒
	 */
	public boolean addData(String key,T data,int second){
		if(second<0){
			log.error("Set Time Less Than 0");
			return false;
		}
		
		Long timekey;
		if(second==0){
			timekey=0L;
		}else{
			timekey=Long.valueOf(DateUtil.dateToUTC()+second);
		}
		
		 write.lock();
		try {
			List<String> list;
			if(!keyMap.containsKey(timekey)){
				list=new ArrayList<String>();
			}else {
				list=keyMap.get(timekey);
			}
			
			list.add(key);
			keyMap.put(timekey, list);
			
			//记录每个key存活到的时间
			if(timekey!=0) {
				checkTime.put(key, timekey);
			}
			
			if(!dataMap.containsKey(key)){
				dataMap.put(key, data);
			}
			
			System.out.println("添加数据:"+key+"  "+data+"  keyMap:"+JsonUtil.toJson(keyMap)+" dataMap:"+JsonUtil.toJson(dataMap));
		} catch (Exception e) {
			log.error("Add Key:"+key+" To Data "+data+" Error",e);
			return false;
		}finally {
			 // 释放写锁
            write.unlock();
		}
		return true;
	}
	
	private class clearTime extends TimerTask{

		@Override
		public void run() {
			Long time=DateUtil.dateToUTC();
			
			if(keyMap.containsKey(time)){
				
				//写入锁
				 write.lock();
				try {
					List<String> list=keyMap.get(time);
					for(String key:list){
						//验证key是否续时，时间相同删除数据
						if(checkTime.containsKey(key)&&checkTime.get(key)==time) {
							//清除数据
							if(dataMap.containsKey(key)){
								dataMap.remove(key);
							}
						}
					}
					
					keyMap.remove(time);
				} catch (Exception e) {
					e.printStackTrace();
				}finally {
					 // 释放写锁
		            write.unlock();
				}
			}
			
		}
		
	}

}
